package club.dingzm.ddxcdemo.model.websocket;

import club.dingzm.ddxcdemo.common.entity.Result;
import club.dingzm.ddxcdemo.common.utils.MD5Util;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.FileCopyUtils;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @Classname UploadFileBytesController
 * @Description TODO
 * @Date 2021/8/12 14:55
 * @Created by Upenv-5600x2
 */
@Component
@Slf4j
@ServerEndpoint("/WebSocketUpload/{userId}/{cacheId}") //此注解相当于设置访问URL
public class WebSocketUploadServer  {

    private static String uploadpath;

    @Value(value = "${jeecg.path.upload}")
    public void setUploadpath(String uploadpath) {
        WebSocketUploadServer.uploadpath = uploadpath;
    }

    private Session session;
    private String userId;

    private FileMessage fileMessage;

    private static CopyOnWriteArraySet<WebSocketUploadServer> webSockets =new CopyOnWriteArraySet<>();
    private static Map<String,Session> sessionPool = new HashMap<String,Session>();

    @OnOpen
    public void onOpen(Session session, @PathParam(value="userId")String userId) {
        try {
            this.session = session;
            this.userId = userId;
            webSockets.add(this);
            sessionPool.put(userId, session);
            log.info("【WebSocketUpload 消息】有新的连接，总数为:"+webSockets.size());
        } catch (Exception e) {
        }
    }

    @OnClose
    public void onClose() {
        try {
            webSockets.remove(this);
            sessionPool.remove(userId);
            log.info("【WebSocketUpload 消息】连接断开，总数为:"+webSockets.size());
        } catch (Exception e) {
        }
    }


    @OnMessage
    public void onMessage(String message, @PathParam("cacheId") String cacheId) {
        //todo 现在有个定时任务刷，应该去掉
        log.debug("【WebSocketUpload 消息】收到客户端消息:"+message);
        //前端传过来的消息都是一个json
        this.fileMessage = JSONUtil.toBean(message,FileMessage.class);
        session.getAsyncRemote().sendText(JSONUtil.toJsonStr(Result.ok("收到更新文件内容")));
    }
    /**
     * 该方法用于接收字节流数组
     *
     * @param message 文件字节流数组
     * @param cacheId 临时缓存Id
     */
    @OnMessage
    public void onMessage(byte[] message, @PathParam("cacheId") String cacheId) {

        String fileTempName = fileMessage.getStart()+"-"+fileMessage.getFileName();
        String ctxPath = uploadpath+ File.separator+"app"+ File.separator+cacheId+File.separator;
        //将流写入文件
        try {

            File file1=new File(ctxPath+fileTempName+".temp");
            File fileTemp = new File( ctxPath );
            if (!fileTemp.exists()) {
                fileTemp.mkdirs();// 创建文件根目录
            }
            //保存当前文件
            FileCopyUtils.copy(message, file1);


            session.getAsyncRemote().sendText(JSONUtil.toJsonStr(Result.ok("收到文件")));

            // 如果 是最后一个分片文件 那么进行 临时文件合并
            if ( fileMessage.getStart().intValue() == fileMessage.getEnd() ){
                File file2 = new File(ctxPath + fileMessage.getFileName() + ".temp");
                if ( !file2.exists()){
                    file2.createNewFile();
                }
                RandomAccessFile resFile=new RandomAccessFile(ctxPath+fileMessage.getFileName()+".temp", "rw");
                FileInputStream in = null;
                for (int i = 0; i <= fileMessage.getEnd() ; i++) {

                    File temp = new File(ctxPath + i + "-" + fileMessage.getFileName() + ".temp");
                    if (temp.exists()){
                        in = new FileInputStream(temp);
                        int len;
                        byte[] bytes = new byte[1024];
                        while ((len = in.read(bytes)) >= 0 ) {
                            resFile.write(bytes,0,len);
                        }
                        if (in != null){
                            in.close();
                        }
                    }
                    temp.delete();

                }
                if (in != null){
                    in.close();
                }
                resFile.close();
                file2.renameTo(new File(ctxPath + fileMessage.getFileName()));
                String fileMD5String = MD5Util.getFileMD5String(ctxPath + fileMessage.getFileName() );
                if ( !fileMD5String.equals(fileMessage.getMd5())){
                    //校验文件失败
                    session.getAsyncRemote().sendText(JSONUtil.toJsonStr(Result.error("校验文件失败")));
                }else {
                    //文件写入成功，返回一个ok
                    session.getAsyncRemote().sendText(JSONUtil.toJsonStr(Result.ok("文件成功完整上传："+ctxPath + fileMessage.getFileName())));
                }

                // TODO 解析文件
            }

        }catch (Exception e){
            e.printStackTrace();
            session.getAsyncRemote().sendText(JSONUtil.toJsonStr(Result.error("服务器异常！无法写入文件")));
            return;
        }
    }

}
